package bma.common.thrift.ai;

import org.apache.thrift.TApplicationException;
import org.apache.thrift.TBase;
import org.apache.thrift.TException;
import org.apache.thrift.TFieldIdEnum;
import org.apache.thrift.protocol.TMessage;
import org.apache.thrift.protocol.TMessageType;
import org.apache.thrift.protocol.TProtocol;

import bma.common.langutil.ai.stack.AIStack;
import bma.common.langutil.ai.stack.AIStackConvert;

public class AIThriftInvokerTrait {

	public static <TYPE> AIStack<TProtocol> invoke(final AIStack<TYPE> stack,
			TProtocol out, final int seqid, final TBase result,
			final String name, TBase avgs) throws TException {
		out.writeMessageBegin(new TMessage(name, TMessageType.CALL, seqid));
		avgs.write(out);
		out.writeMessageEnd();
		out.getTransport().flush();
		if (result != null) {
			return new AIStackConvert<TProtocol, TYPE>(stack) {

				@Override
				protected boolean convert(TProtocol in) {
					try {
						TMessage msg = in.readMessageBegin();
						if (msg.type == TMessageType.EXCEPTION) {
							TApplicationException x = TApplicationException
									.read(in);
							in.readMessageEnd();
							throw x;
						}
						if (msg.seqid != seqid) {
							throw new TApplicationException(
									TApplicationException.BAD_SEQUENCE_ID,
									name + " failed: out of sequence response");
						}
						result.read(in);
						in.readMessageEnd();

						TFieldIdEnum field = result.fieldForId(0);
						if (field != null) {
							return successConvert((TYPE) result
									.getFieldValue(field));
						} else {
							return successConvert(null);
						}
					} catch (Exception e) {
						return failure(e);
					}
				}
			};
		} else {
			return new AIStackConvert<TProtocol, TYPE>(stack) {
				@Override
				protected boolean convert(TProtocol result) {
					return true;
				}
			};
		}

	}
}
